package com.sunricher.telinkblemeshlib;

import android.util.ArraySet;

// @androidx.annotation.RequiresApi(api = Build.VERSION_CODES.M)
public class MeshDeviceType {

    private int rawValue1;
    private int rawValue2;
    private Category category;
    private ArraySet<Capability> capabilities = new ArraySet<>();

    private LightType lightType = LightType.onOff;

    private SensorType sensorType = SensorType.none;
    private UniversalRemoteType universalRemoteType = UniversalRemoteType.none;
    private CurtainType curtainType = CurtainType.normal;

    public MeshDeviceType(int deviceType, int subDeviceType) {

        this.rawValue1 = deviceType;
        this.rawValue2 = subDeviceType;

        switch (deviceType) {

            case 0x01:

                this.category = Category.light;
                this.capabilities = this.getLightCapabilities(subDeviceType);
                this.sensorType = this.getLightSensorType(subDeviceType);
                break;

            case 0x02:
            case 0x03:
            case 0x0A:
            case 0x0B:
            case 0x0C:
            case 0x0D:
            case 0x0E:
            case 0x12:
            case 0x13:
            case 0x14:
                this.category = Category.remote;
                break;

            case 0x16:
                this.category = Category.customPanel;
                break;

            case 0x04:
                this.category = Category.sensor;
                break;

            case 0x05:
                this.category = Category.transmitter;
                break;

            case 0x06:
                this.category = Category.peripheral;
                break;

            case 0x07:
                this.category = Category.curtain;
                ArraySet<Capability> capabilities = new ArraySet<>();
                this.capabilities = capabilities;
                if (subDeviceType == 0x02) {
                    curtainType = CurtainType.blind;
                } else if (subDeviceType == 0x03) {
                    curtainType = CurtainType.dooya;
                } else {
                    curtainType = CurtainType.normal;
                }
                break;

            case 0x08:
                this.category = Category.outlet;
                break;

            case 0x50:

                if (rawValue2 == 0x02) {

                    this.category = Category.rfPa;

                } else {

                    this.category = Category.bridge;
                }
                break;

            case 0x10:
                category = Category.universalRemote;
                if (rawValue2 == 0x06) {
                    universalRemoteType = UniversalRemoteType.k5WithKnob;
                } else if (rawValue2 == 0x07) {
                    universalRemoteType = UniversalRemoteType.k12WithKnob;
                }
                break;

            case 0x09:
            default:
                this.category = Category.unsupported;
                break;
        }
    }

    public LightType getLightType() {
        return lightType;
    }

    public static byte getLightTypeValue(LightType lightType) {
        switch (lightType) {
            case onOff: {
                return (byte) 0x00;
            }
            case dim: {
                return (byte) 0x01;
            }
            case cct: {
                return (byte) 0x02;
            }
            case rgb: {
                return (byte) 0x03;
            }
            case rgbw: {
                return (byte) 0x04;
            }
            case rgbCct: {
                return (byte) 0x05;
            }
            case doubleChannelsOnOff: {
                return (byte) 0x06;
            }
            default:
                return (byte) 0x00;
        }
    }

    public SensorType getSensorType() {
        return sensorType;
    }

    public UniversalRemoteType getUniversalRemoteType() {
        return universalRemoteType;
    }

    public CurtainType getCurtainType() {
        return curtainType;
    }

    private ArraySet<Capability> getLightCapabilities(int subDeviceType) {

        ArraySet<Capability> capabilities = new ArraySet<>();

        switch (subDeviceType) {

            // OnOff
            case 0x12:
            case 0x14:
            case 0x30:
            case 0x60:
                capabilities.add(Capability.onOff);
                lightType = LightType.onOff;
                break;

            // DIM
            case 0x11:
            case 0x13:
            case 0x31:
            case 0x38:
            case 0x61:
            case 0x36:
            case 0x66:
            case 0x20: // Power Metering
            case 0x28: // NFC DIM
            case 0x2A: // NFC DIM 2
            case 0x3C: // Microwave Motion Sensors 3C-3F
            case 0x3D:
            case 0x3E:
            case 0x3F:
            case 0x15:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.brightness);
                lightType = LightType.dim;
                break;

            case 0x16:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.channel1OnOff);
                capabilities.add(Capability.channel2OnOff);
                lightType = LightType.doubleChannelsOnOff;
                break;

            // CCT
            case 0x08:
            case 0x29: // NFC CCT
            case 0x2B: // NFC CCT 2
            case 0x32:
            case 0x37:
            case 0x39:
            case 0x62:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.brightness);
                capabilities.add(Capability.colorTemperature);
                lightType = LightType.cct;
                break;

            // RGB
            case 0x33:
            case 0x63:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.brightness);
                capabilities.add(Capability.rgb);
                lightType = LightType.rgb;
                break;

            // RGBW
            case 0x34:
            case 0x64:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.brightness);
                capabilities.add(Capability.rgb);
                capabilities.add(Capability.white);
                lightType = LightType.rgbw;
                break;

            // RGB CCT
            case 0x35:
            case 0x65:
                capabilities.add(Capability.onOff);
                capabilities.add(Capability.brightness);
                capabilities.add(Capability.rgb);
                capabilities.add(Capability.colorTemperature);
                lightType = LightType.rgbCct;
                break;

        }

        return capabilities;
    }

    private SensorType getLightSensorType(int subDeviceType) {

        switch (subDeviceType) {
            case 0x3C:
            case 0x3D:
            case 0x3E:
            case 0x3F:
            case 0x40:
                return SensorType.microwaveMotion;

            default:
                return SensorType.none;
        }
    }

    public int getRawValue1() {
        return rawValue1;
    }

    public int getRawValue2() {
        return rawValue2;
    }

    public Category getCategory() {
        return category;
    }

    public ArraySet<Capability> getCapabilities() {
        return capabilities;
    }

    public String getCategoryTitle() {

        switch (this.category) {

            case light:
                return "Light";

            case remote:
                return "Remote";

            case sensor:
                return "Sensor";

            case transmitter:
                return "Transmission module";

            case peripheral:
                return "Peripheral";

            case curtain:
                return "Curtain";

            case outlet:
                return "Outlet";

            case bridge:
                return "Bridge";

            case rfPa:
                return "RF PA";

            case customPanel:
                return "Custom Panel";

            default:
                return "Unsupported";
        }
    }

    public String getCapabilityTitle(Capability capability) {

        switch (capability) {

            case onOff:
                return "OnOff";

            case brightness:
                return "Brightness";

            case colorTemperature:
                return "Color temperature";

            case white:
                return "White";

            case rgb:
                return "RGB";

            case channel1OnOff:
                return "Channel 1 OnOff";
            case channel2OnOff:
                return "Channel 2 OnOff";

            default:
                return "Unsupported";
        }
    }

    @Override
    public boolean equals(Object obj) {

        if (obj == null) {
            return false;
        }
        if (!obj.getClass().equals(this.getClass())) {
            return false;
        }

        MeshDeviceType other = (MeshDeviceType) obj;

        return this.rawValue1 == other.rawValue1 && this.rawValue2 == other.rawValue2;
    }

    public boolean isSupportMeshAdd() {

        switch (this.category) {

            case light:
            case curtain:
            case bridge:
            case outlet:
                return true;

            default:
                return false;
        }
    }

    public boolean isSafeConnection() {

        switch (this.category) {

            case light:
            case curtain:
            case outlet:
            case rfPa:
                return true;

            default:
                return false;
        }
    }

    /**
     * This is a light, support set sensor ID and sensor actions.
     * Set sensor actions will be deprecated.
     *
     * @return Does it support set sensor ID or sensor actions.
     */
    public boolean isSupportSensorAction() {
        if (category == Category.curtain) {
            return true;
        }

        if (category != Category.light) {
            return false;
        }
        if (capabilities.isEmpty()) {
            return false;
        }
        if (sensorType != SensorType.none) {
            return false;
        }
        if (isBleUartModule()) {
            return false;
        }
        return true;
    }

    public boolean isSupportPowerOnState() {
        if (category != Category.light) {
            return false;
        }
        int value = this.rawValue2;
        if (value >= 0x11 && value <= 0x1F) {
            return true;
        }
        if (value == 0x28 || value == 0x2F) {
            return true;
        }
        if (value >= 0x30 && value <= 0x3F) {
            return true;
        }
        if (value >= 0x60 && value <= 0x6F) {
            return true;
        }
        if (value >= 0x70 && value <= 0x7F) {
            return true;
        }
        return false;
    }

    public boolean isSupportChangeDeviceType() {
        if (category != Category.light) {
            return false;
        }
        int value = this.rawValue2;
        if (value >= 0x30 && value <= 0x35) {
            return true;
        }
        if (value >= 60 && value <= 0x65) {
            return true;
        }
        return false;
    }

    public void updateToNewLightType(MeshDeviceType.LightType newLightType) {
        int newValue = (int) MeshDeviceType.getLightTypeValue(newLightType) & 0xFF;
        rawValue2 = (rawValue2 & 0xF0) | newValue;
        this.capabilities = this.getLightCapabilities(rawValue2);
        this.sensorType = this.getLightSensorType(rawValue2);
    }

    public boolean isBleUartModule() {
        if (category != Category.light) {
            return false;
        }
        int type = rawValue2 & 0xF0;
        switch (type) {
            case 0x90:
            case 0xC0:
            case 0xA0:
            case 0xD0:
                return true;
            default:
                return false;
        }
    }

    public enum Category {
        light,
        remote,
        sensor,
        transmitter,
        peripheral,
        curtain,
        outlet,
        bridge,
        rfPa,
        customPanel,
        unsupported,
        universalRemote,
    }

    public enum Capability {
        onOff,
        brightness,
        colorTemperature,
        white,
        rgb,
        channel1OnOff,
        channel2OnOff,
    }

    public enum LightType {

        onOff,
        dim,
        cct,
        rgb,
        rgbw,
        rgbCct,
        doubleChannelsOnOff
    }

    public enum SensorType {

        none,
        microwaveMotion
    }

    public enum UniversalRemoteType {
        none,
        k5WithKnob,
        k12WithKnob,
    }

    public enum CurtainType {
        normal,
        blind,
        dooya
    }

}
